﻿#include <rxplugin.h>
#include <metaproperty.h>
#include <metasignal.h>

#include "RXNode.h"
#include "RXEntity.h"
#include "RXWorld.h"
#include "RXNodeCreationInfo.h"


DECL_VARIANT_TYPE(RXECSDef::CreationPolicy)

struct NodeRegisterInfo
{
	RXNode* node;
	ConnectionRegistry registry;
};

struct RXWorld::Private
{
	RXECSDef::NodeId MaxId = 0;

	Private(RXWorld* front) {
		this->front = front;
	}

	RXECSDef::NodeId AllocaId() {
		MaxId++;
		return MaxId;
	}

	void DoRegisterNode(RXNode* entity) {
		if (!entity) {
			return;
		}
		auto id = AllocaId();
		entity->m_id = id;
		entity->m_world = front;

		
		NodeRegisterInfo info;
		auto meta = entity->GetMetaInfo();

		void* root_void = dynamic_cast<void*>(entity);
		for (int i = 0; i < meta.PropertyCount(); i++) {
			auto prop = meta.GetProperty(i);

			//对节点所有的属性进行监控
			if (prop.hasNotifier()) {
				GenericSignal* signal = prop.GetNotifier().GetSignal(root_void);
				auto connection = signal->UnSafeBind([=](const void**) {
					for (const auto &l : m_listeners) {
						l->NodePropertyChanged(id, i, prop.GetValue(root_void));
					}
				});
				info.registry.Append(connection);
			}
		}
		
		info.node = entity;
		m_nodeMap[id] = info;
		

		for (const auto & i : m_listeners) {
			i->NodeSpawned(entity,entity == m_root.get());
		}

		for (const auto &i : entity->GetChildren()) {
			DoRegisterNode(dynamic_cast<RXNode*>(i));
		}
	}

	void DoUnRegisterNode(RXNode* node) {
		if (!node) {
			return;
		}

		auto nodeId = node->m_id;

		m_nodeMap.erase(nodeId);
		
		for (const auto & i : m_listeners) {
			i->NodeDeleted(nodeId);
		}

		node->m_id = 0;
		node->m_world = NULL;

		for (const auto &i : node->GetChildren()) {
			DoUnRegisterNode(dynamic_cast<RXNode*>(i));
		}



	}

	void RegisterNode(RXNode* node) {
		std::lock_guard<std::mutex> lock(m_mutex);
		DoRegisterNode(node);
	}

	void UnRegisterNode(RXNode* node) {
		std::lock_guard<std::mutex> lock(m_mutex);
		DoUnRegisterNode(node);
	}

	std::unique_ptr<RXEntity> m_root;
	ThreadSafe::ObjectRegistry<RXNode> m_registry;

	std::unordered_map<RXECSDef::NodeId, NodeRegisterInfo> m_nodeMap;
	std::mutex m_mutex;

	std::map<std::string, MetaInfo> m_classMap;

	std::vector<std::shared_ptr<RXPluginLoader>> m_loaded_plugin;

	RXWorldEventListenrList m_listeners;

	RXWorld* front;
};

RXWorld::RXWorld():_P(new Private(this))
{
}

RXWorld::~RXWorld()
{
}

void RXWorld::AddWorldListener(RXWorldEventListenrPtr e)
{
	_P->m_listeners.push_back(e);
}

void RXWorld::RemoveWorldListener(RXWorldEventListenrPtr e)
{
	for (auto it = _P->m_listeners.begin(); it != _P->m_listeners.end(); it++) {
		if (*it == e)
		{
			_P->m_listeners.erase(it);
			return;
		}
	}
}

std::chrono::system_clock RXWorld::GetWorldTime()
{
	return std::chrono::system_clock();
}

std::chrono::milliseconds RXWorld::GetWorldTimeDelta()
{
	return std::chrono::milliseconds();
}

bool RXWorld::LoadLibrary(const char * lib)
{
	std::shared_ptr<RXPluginLoader> loader(new RXPluginLoader());
	if (!loader->load(lib))
	{
		return false;
	}
	_P->m_loaded_plugin.push_back(loader);

	auto plugin = loader->GetPluginInterface();

	for (auto &i : plugin->ClassNames()) {
		MetaInfo meta = plugin->LoadClass(i.c_str());
		if (RXNode::staticMetaInfo().IsBaseOf(meta)) {//仅注册RXNode的子类
			RegisterClassImp(meta, meta.ClassName().c_str());
		}
	}
}

RXNode* RXWorld::Spawn(const char * className, RXEntity* parent)
{
	if (_P->m_classMap.count(className)) {
		std::cerr << "RXWorld::Spawn :生成对象失败,类型" << className << "未注册" << std::endl;
		return NULL;
	}

	return SpawnImp(_P->m_classMap.at(className), parent);
}

void RXWorld::RegisterClass(const MetaInfo & info)
{
	RegisterClassImp(info, info.ClassName().c_str());
}

RXEntity * RXWorld::GetRootEntity()
{
	return _P->m_root.get();
}

void RXWorld::SetRootEntity(RXEntity * root)
{
	if (_P->m_root) {
		_P->m_root.reset();
	}

	_P->m_root.reset(root);

	if (_P->m_root) {
		_P->m_root->m_world = this;
		_P->RegisterNode(_P->m_root.get());
	}
}

RXNode * RXWorld::GetNode(RXECSDef::NodeId id)
{
	std::lock_guard<std::mutex>(_P->m_mutex);

	return _P->m_nodeMap.at(id).node;
}

void RXWorld::RegisterNode(RXNode * node)
{
	_P->RegisterNode(node);
}

void RXWorld::UnRegisterNode(RXNode * node)
{
	_P->UnRegisterNode(node);
}

RXECSDef::NodeId RXWorld::AllocNodeId()
{
	return _P->AllocaId();
}

RXNode * RXWorld::SpawnImp(const MetaInfo & m, RXEntity* parent)
{
	void* ret = m.Create();

	if (!ret) {
		return NULL;
	}

	RXNode* node = m.MetaCast<RXNode>(ret);

	if (!parent) {
		parent = _P->m_root.get();
	}

	node->SetParent(parent);

	return node;
}

void RXWorld::RegisterClassImp(const MetaInfo & m,const char* name)
{
	auto ClassNameDuplicated = _P->m_classMap.count(name);
	assert(ClassNameDuplicated);
	
	_P->m_classMap[name] = m;
}

void RXWorld::PostEventToShadowNode(RXNode * target, ThreadSafe::Event * event)
{
	for (auto i : _P->m_listeners) {
		i->NodeEventToShadow(target->GetNodeId(), event);
	}
}
